/*
 *  This file is part of LifeBudget - Copyright 2010 Clifton Eaton
 *  ------------------------------------------------------------------
 *  LifeBudget is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  LifeBudget is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with LifeBudget.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.lifebudget.app.client.mvc.controller;

import java.util.List;

import org.lifebudget.app.client.events.AppEvents;
import org.lifebudget.app.client.mvc.model.Category;
import org.lifebudget.app.client.mvc.model.CategoryAmount;
import org.lifebudget.app.client.mvc.model.PaycheckCalculator;
import org.lifebudget.app.client.mvc.view.paycheck.PaycheckCalculatorEditorView;
import org.lifebudget.app.client.mvc.view.paycheck.PaycheckCalculatorSummaryView;
import org.lifebudget.app.client.mvc.view.paycheck.PaycheckCalculatorView;
import org.lifebudget.app.client.service.CategoryService;
import org.lifebudget.app.client.service.CategoryServiceAsync;
import org.lifebudget.app.client.service.PaycheckCalculatorService;
import org.lifebudget.app.client.service.PaycheckCalculatorServiceAsync;

import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * Controller class for PaycheckCalculator events and views.
 */
public class PaycheckCalculatorController extends Controller {

	/** The paycheck calculator view. */
	private PaycheckCalculatorView paycalcView;
	
	/** The paycheck calculator service. */
	private PaycheckCalculatorServiceAsync paycheckService;
	
	/** The paycheck calculator summary view. */
	private PaycheckCalculatorSummaryView paycalcSummaryView;
	
	/** The paycheck calculator editor view. */
	private PaycheckCalculatorEditorView paycalcEditorView;
	
	/** The category service. */
	private CategoryServiceAsync categoryService;

	/**
	 * Instantiates a new paycheck calculator controller, registering all
	 * events handled by the controller.
	 */
	public PaycheckCalculatorController() {

		registerEventTypes(AppEvents.Init);
		registerEventTypes(AppEvents.PaycheckCalcSelected);
		registerEventTypes(AppEvents.NewPaycheckCalc);
		registerEventTypes(AppEvents.PaycheckCalcUpdated);
		registerEventTypes(AppEvents.DeletePaycheckCalc);
		registerEventTypes(AppEvents.PaycheckListLoaded);
		registerEventTypes(AppEvents.PaycheckCalcSelectionCleared);
		registerEventTypes(AppEvents.CategoryAmountRemoved);
		registerEventTypes(AppEvents.CategoryAmountsUpdated);
		registerEventTypes(AppEvents.UpdateSummary);
		registerEventTypes(AppEvents.RefreshCategory);

	}

	/* (non-Javadoc)
	 * @see com.extjs.gxt.ui.client.mvc.Controller#initialize()
	 */
	public void initialize() {
		paycalcView = new PaycheckCalculatorView(this);
		paycalcSummaryView = new PaycheckCalculatorSummaryView(this);
		paycalcEditorView = new PaycheckCalculatorEditorView(this);
		paycheckService = GWT.create(PaycheckCalculatorService.class);
		categoryService = GWT.create(CategoryService.class);
	}

	/* (non-Javadoc)
	 * @see com.extjs.gxt.ui.client.mvc.Controller#handleEvent(com.extjs.gxt.ui.client.mvc.AppEvent)
	 */
	@Override
	public void handleEvent(final AppEvent event) {
		if (event.getType() == AppEvents.Init) {
			onInit(event);

		}
		if (event.getType() == AppEvents.PaycheckCalcSelected) {
			onPaycheckCalcSelected(event);
		}
		if (event.getType() == AppEvents.PaycheckListLoaded) {
			onPaycheckListLoaded(event);

		}
		if (event.getType() == AppEvents.NewPaycheckCalc) {
			onNewPaycheckCalc(event);
		}
		if (event.getType() == AppEvents.DeletePaycheckCalc) {
			onDeletePaycheckCalc(event);
		}
		if (event.getType() == AppEvents.PaycheckCalcSelectionCleared) {
			onPaycheckCalcSelectionCleared(event);
		}
		if (event.getType() == AppEvents.CategoryAmountRemoved) {
			onCategoryAmountRemoved(event);
		}
		if (event.getType() == AppEvents.CategoryAmountsUpdated) {
			onCategoryAmountsUpdated(event);
		}
		if (event.getType() == AppEvents.PaycheckCalcUpdated) {
			onPaycheckCalcUpdated(event);
		}
		if (event.getType() == AppEvents.UpdateSummary) {
			forwardToView(paycalcSummaryView, event);
		}
		if (event.getType() == AppEvents.RefreshCategory) {
			onRefresh(event);
		}

	}

	/**
	 * Handles the <code>RefreshCategory</code> event, forwarding it
	 * to the {@link PaycheckCalculatorEditorView}.
	 *
	 * @param event the <code>RefreshCategory</code> event
	 */
	private void onRefresh(final AppEvent event) {
		GWT.log("RefreshCategory recieved on controller");
		forwardToView(paycalcEditorView, event);
	}

	/**
	 * Handles the <code>PaycheckCalcSelected</code> event, forwarding it
	 * to the {@link PaycheckCalculatorEditorView}.
	 *
	 * @param event the <code>PaycheckCalcSelected</code> event
	 */
	private void onPaycheckCalcSelected(final AppEvent event) {
		// GWT.log("PaycheckCalculatorController recieved AppEvent PaycheckCalcSelected forwarding to editor view");
		forwardToView(paycalcEditorView, event);
	}

	/**
	 * Handles the <code>PaycheckListLoaded</code> event, getting all categories,
	 * and forwarding the event and the category list to the {@link PaycheckCalculatorEditorView}.
	 *
	 * @param event the <code>PaycheckListLoaded</code> event
	 */
	private void onPaycheckListLoaded(final AppEvent event) {
		// GWT.log("PaycheckCalculatorEditorController received AppEvent PaycheckListLoaded, forwarding to view");
		categoryService.getAllCategories(false, new AsyncCallback<List<Category>>() {

			@Override
			public void onFailure(Throwable caught) {
				Dispatcher.get().dispatch(AppEvents.Error);

			}

			@Override
			public void onSuccess(List<Category> result) {
				event.setData(result);
				forwardToView(paycalcEditorView, event);

			}
		});
	}

	/**
	 * Handles the <code>PaycheckCalcSelectionCleared</code> event, and forwards it
	 * to the {@link PaycheckCalculatorEditorView} and {@link PaycheckCalculatorSummaryView}.
	 *
	 * @param event the <code>PaycheckCalcSelectionCleared</code> event
	 */
	private void onPaycheckCalcSelectionCleared(final AppEvent event) {
		forwardToView(paycalcEditorView, event);
		forwardToView(paycalcSummaryView, event);
	}

	/**
	 * Handles the <code>CategoryAmountRemoved</code> event, invoking the service to 
	 * remove the {@link CategoryAmount} and then forwarding to the {@link PaycheckCalculatorView}.
	 *
	 * @param event the <code>CategoryAmountRemoved</code> event
	 */
	private void onCategoryAmountRemoved(final AppEvent event) {
		CategoryAmount ca = (CategoryAmount) event.getData();
		paycheckService.removeCategoryAmount(ca, new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				Dispatcher.get().dispatch(AppEvents.Error);
			}

			@Override
			public void onSuccess(Void result) {
				// GWT.log("Successfully removed CategoryAmount");
				forwardToView(paycalcView, event);
			}
		});
	}

	/**
	 * Handles the <code>CategoryAmountsUpdated</code> event, updating the CategoryAmounts 
	 * and returning the updated set to the the {@link PaycheckCalculatorView}.
	 *
	 * @param event the <code>CategoryAmountsUpdated</code> event.
	 */
	private void onCategoryAmountsUpdated(final AppEvent event) {
		GWT.log("CategoryAmountsUpdated event received in controller");
		Object o = event.getData();
		List<CategoryAmount> categoryAmts = (List<CategoryAmount>) event.getData("categoryAmounts");
		Long id = (Long) event.getData("id");
		GWT.log("Calling update on paycheck service with id " + id + " and category amounts " + categoryAmts);
		paycheckService.updateCategoryAmounts(id, categoryAmts, new AsyncCallback<List<CategoryAmount>>() {

			@Override
			public void onSuccess(List<CategoryAmount> result) {
				// GWT.log("Successfully updated CategoryAmounts");
				event.setData(result);
				GWT.log("Forwarding CategoryAmountsUpdated to editor view");
				forwardToView(paycalcView, event);

			}

			@Override
			public void onFailure(Throwable caught) {
				Dispatcher.get().dispatch(AppEvents.Error);
			}
		});
	}

	/**
	 * Handles the <code>PaycheckCalcUpdated</code> event, invoking the service
	 * to update the {@link PaycheckCalculator} and then dispatching a <code>RefreshPaycheck</code>
	 * event.
	 * 
	 *
	 * @param event the <code>PaycheckCalcUpdated</code> event
	 */
	private void onPaycheckCalcUpdated(final AppEvent event) {
		PaycheckCalculator pc = (PaycheckCalculator) event.getData();
		paycheckService.updatePaycheckCalculator(pc, new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				Dispatcher.get().dispatch(AppEvents.Error);

			}

			@Override
			public void onSuccess(Void result) {
				dispatchRefreshPaychecksEvent();

			}
		});
	}

	/**
	 * Dispatches a <code>RefreshPaycheck</code> event and populates it with the current
	 * list of {@link PaycheckCalculator} objects.
	 */
	protected void dispatchRefreshPaychecksEvent() {
		paycheckService.getAllPaycheckCalculators(new AsyncCallback<List<PaycheckCalculator>>() {

			@Override
			public void onFailure(Throwable caught) {
				Dispatcher.get().dispatch(AppEvents.Error);
			}

			@Override
			public void onSuccess(List<PaycheckCalculator> result) {
				Dispatcher.get().dispatch(AppEvents.RefreshPaycheck, result);
			}
		});

	}

	/**
	 * Handles the <code>DeletePaycheckCalc</code> event, invoking the service
	 * to delete the {@link PaycheckCalculator} and then forwarding the event to the
	 * {@link PaycheckCalculatorView}.
	 * 
	 *
	 * @param event the <code>DeletePaycheckCalc</code> event
	 */
	private void onDeletePaycheckCalc(final AppEvent event) {
		PaycheckCalculator pc = (PaycheckCalculator) event.getData();
		paycheckService.deletePaycheckCalculator(pc, new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				Dispatcher.get().dispatch(AppEvents.Error);
			}

			@Override
			public void onSuccess(Void result) {
				forwardToView(paycalcView, event);
			}
		});

	}

	/**
	 * Handles the <code>NewPaycheckCalculator</code> event, saving the {@link PaycheckCalculator}
	 * and then forwarding to the {@link PaycheckCalculatorView}.
	 *
	 * @param event the <code>NewPaycheckCalculator</code> event
	 */
	private void onNewPaycheckCalc(AppEvent event) {
		PaycheckCalculator pc = (PaycheckCalculator) event.getData();
		// GWT.log("NewPaycheckCalc event recieved from view with data " +
		// pc.getName());
		paycheckService.addPaycheckCalculator(pc, new AsyncCallback<PaycheckCalculator>() {

			@Override
			public void onFailure(Throwable caught) {
				Dispatcher.get().dispatch(AppEvents.Error);

			}

			@Override
			public void onSuccess(PaycheckCalculator result) {
				// GWT.log("Successfuly added pc " + result.getName() +
				// " forwarding to paycalcView");
				forwardToView(paycalcView, new AppEvent(AppEvents.NewPaycheckCalc, result));
			}
		});
	}

	/**
	 * Handles the <code>Init</code> event, getting all {@link PaycheckCalculator} objects
	 * from and forwarding to both the {@link PaycheckCalculatorView} and the {@link PaycheckCalculatorEditorView}.
	 *
	 * @param event the <code>Init</code> event
	 */
	private void onInit(final AppEvent event) {
		// GWT.log("PaycheckCalculatorController received AppEvent Init, forwarding to view");
		paycheckService.getAllPaycheckCalculators(new AsyncCallback<List<PaycheckCalculator>>() {

			@Override
			public void onSuccess(List<PaycheckCalculator> result) {
				System.out.println("success");
				event.setData(result);
				forwardToView(paycalcView, event);
				forwardToView(paycalcSummaryView, event);

			}

			@Override
			public void onFailure(Throwable caught) {
				System.out.println("error");
				Dispatcher.get().dispatch(AppEvents.Error);

			}
		});

	}
}
